<template>
  <custom-card class="pro-table" :is-card="styleType === 'one'">
    <query-form
      v-if="queryColumns && queryColumns.length"
      ref="queryFormRef"
      class="pro-table_form"
      :card="styleType === 'two' || styleType === 'three'"
      :query="queryColumns"
      :queryData="queryData"
      :autoSearch="autoSearch"
      :collapsed="collapsed"
      :labelWidth="labelWidth"
      :labelAlign="labelAlign"
      :searchBtnText="searchBtnText"
      :resetBtnText="resetBtnText"
      :firstLineQueryCount="firstLineQueryCount"
      @queryChange="queryChangeHandle"
      @collapsedChange="collapsedChangeHandle"
      @search="searchHandle"
      @reset="resetHandle"
    />

    <custom-card :is-card="styleType === 'two'">
      <query-table
        ref="queryTableRef"
        class="pro-table_main"
        v-bind="props"
        :card="styleType === 'three'"
        :loading="tableLoading"
        :data="props.data || columnData"
        :page-index="page"
        :page-size="size"
        :max-height="props.autoHeight ? tableMaxHeight : props.maxHeight"
        @refresh="searchHandle"
      >
        <template v-for="(_, slot) in $slots" v-slot:[slot]>
          <slot :name="slot"></slot>
        </template>
      </query-table>

      <query-pagination
        v-if="pagination"
        class="pro-table_pagination"
        v-model:page="page"
        v-model:size="size"
        :card="styleType === 'three'"
        :total="props.data ? $props.total : total"
      />
    </custom-card>
  </custom-card>
</template>

<script lang="ts" setup name="ProTable">
  import QueryForm from './components/query-form'
  import QueryTable from './components/query-table/index.vue'
  import qs from 'qs'
  import { proTableProps } from './props'
  import {
    otherRelativeHeight,
    paginationRelativeHeight,
    queryFormRelativeHeight
  } from './constant'

  const props: any = defineProps(proTableProps)
  const emits = defineEmits([
    'queryChange',
    'search',
    'reset',
    'collapsedChange'
  ])
  const queryFormRef = ref<any | null>(null)
  const queryTableRef = ref<InstanceType<typeof QueryTable> | null>(null)

  const columnData = ref([])
  const tableLoading = ref(false)
  const queryData = ref({})
  const tableMaxHeight = ref(0)

  const page = ref(props.defaultPageIndex)
  const size = ref(props.defaultPageSize)
  const total = ref(0)

  const queryColumns = computed(() => {
    let queryList: any[] = []
    if (props.query) {
      queryList = props.query
    } else {
      props.columns?.forEach((item) => {
        const { query, title, key } = item
        if (query && title && key) {
          if (query.type === 'select') {
            query.dictOptions = query.dictOptions || item.dictOptions
            query.dictCode = query.dictCode || item.dictCode
          }
          queryList.push({ title, key, ...query })
        }
      })
    }
    queryList.sort((a, b) => (a.order || 999) - (b.order || 999))
    return queryList
  })

  const setDefaulQueryData = (isInit = false) => {
    let defaulQueryData = {}
    queryColumns.value.forEach((item) => {
      const { key, defaultValue } = item
      if (key && defaultValue) {
        if (
          item.type === 'daterange' &&
          Array.isArray(defaultValue) &&
          Array.isArray(key)
        ) {
          const [dateStart, dateEnd] = defaultValue
          defaulQueryData[key[0]] = dateStart
          defaulQueryData[key[1]] = dateEnd
        } else {
          defaulQueryData[key] = defaultValue
        }
      }
    })

    if (isInit) {
      defaulQueryData = {
        ...queryData.value,
        ...defaulQueryData
      }
    }
    queryData.value = defaulQueryData
  }

  const initqueryData = () => {
    const hash = window.location.hash
    const hashData: any = qs.parse(hash.replace('#', '')) || {}
    page.value = hashData.page ? parseInt(hashData.page) : page.value
    size.value = hashData.size ? parseInt(hashData.size) : size.value
    delete hashData.page
    delete hashData.size
    queryData.value = hashData
    setDefaulQueryData(true)
    pathHash()
  }

  const fetchData = async () => {
    try {
      if (props.data?.length || !props.request) return
      tableLoading.value = true
      const { data = [], total: dataTotal = 0 } = await props.request(
        {
          pageIndex: page.value,
          pageSize: size.value
        },
        queryData.value
      )
      tableLoading.value = false
      columnData.value = data
      total.value = dataTotal
    } catch (e) {
      console.log(e)
      tableLoading.value = false
    }
  }

  const searchHandle = async (form = {}) => {
    queryData.value = form
    searchEmit()
    fetchData()
    props.cache && pathHash()
  }

  const searchEmit = () => {
    emits('search', { ...queryData.value, page: page.value, size: size.value })
  }

  const queryChangeHandle = (value, item, type) => {
    emits('queryChange', value, item, type)
  }

  const resetHandle = () => {
    setDefaulQueryData()
    searchEmit()
    emits('reset')
    fetchData()
    props.cache && pathHash()
  }

  const collapsedChangeHandle = (value) => {
    emits('collapsedChange', value)
    setTableMaxHeight()
  }

  const setTableMaxHeight = () => {
    if (!props.autoHeight) return
    nextTick(() => {
      const bodyClientHeight = document.body.clientHeight
      const queryFormClientHeight =
        queryFormRef.value?.$el.clientHeight ||
        queryFormRelativeHeight[props.styleType]
      const paginationClientHeight = props.pagination
        ? 70
        : paginationRelativeHeight[props.styleType]

      tableMaxHeight.value =
        bodyClientHeight -
        queryFormClientHeight -
        paginationClientHeight -
        otherRelativeHeight[props.styleType] +
        props.relativeHeight
    })
  }

  watch(page, () => {
    searchEmit()
    fetchData()
    props.cache && pathHash()
  })
  watch(size, () => {
    searchEmit()
    fetchData()
    props.cache && pathHash()
  })

  function pathHash() {
    window.location.hash = qs.stringify({
      page: page.value,
      size: size.value,
      ...queryData.value
    })
  }

  fetchData()
  props.cache && initqueryData()
  props.autoHeight && setTableMaxHeight()

  onMounted(() => {
    window.addEventListener('resize', setTableMaxHeight)
  })
  onUnmounted(() => {
    window.removeEventListener('resize', setTableMaxHeight)
  })

  defineExpose({
    reload: fetchData,
    search: (params: Record<string, string>) => {
      queryFormRef.value?.search(params)
    },
    reset: () => {
      queryFormRef.value?.reset()
    },
    excelExportDownload: () => {
      queryTableRef.value?.excelExportDownload()
    }
  })
</script>

<style lang="less" scoped>
  .pro-table {
    &_form {
      margin-bottom: 20px;
    }

    &_main {
      margin-bottom: 20px;
    }
  }
</style>
